<?php

namespace GanYiInfo\Utils;

class Signature
{
    /**
     * @param array $params
     * @param $privateKey
     * @param $key
     * @return string
     */
    public function generateSign(array $params, $privateKey, $key)
    {
        if (strrpos($privateKey, '.pem')) {
            $pKey = openssl_pkey_get_private(file_get_contents($privateKey));
        } else {
            $pKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
                wordwrap($privateKey, 64, "\n", true) .
                "\n-----END RSA PRIVATE KEY-----";
        }

        openssl_sign($this->getSignContent($params, $key), $sign, $pKey, OPENSSL_ALGO_SHA256);

        if (strrpos($privateKey, '.pem')) {
            openssl_free_key($pKey);
        }

        return base64_encode($sign);
    }

    /**
     * @param array $data
     * @param $sign
     * @param $publicKey
     * @param $key
     * @return bool
     */
    public function verify(array $data, $sign, $publicKey, $key)
    {
        if (strrpos($publicKey, '.pem')) {
            $pubKey = openssl_pkey_get_public(file_get_contents($publicKey));
        } else {
            $pubKey = "-----BEGIN PUBLIC KEY-----\n" .
                wordwrap($publicKey, 64, "\n", true) .
                "\n-----END PUBLIC KEY-----";
        }

        $result = (openssl_verify($this->getSignContent($data, $key), base64_decode($sign), $pubKey, OPENSSL_ALGO_SHA256) === 1);

        if (strrpos($publicKey, '.pem')) {
            openssl_free_key($pubKey);
        }

        return $result;
    }

    /**
     * @param array $params
     * @param $key
     * @return string
     */
    public function getSignContent(array $params, $key)
    {
        ksort($params);
        $stringToBeSigned = "";

        foreach ($params as $k => $v) {
            if (false === Str::checkEmpty($v) && $k != 'sign') {
                // 转换成目标字符集
                $stringToBeSigned .= "{$k}" . "=" . "{$v}" . "&";
            }
        }
        unset ($k, $v);

        $stringToBeSigned .= 'key=' . $key;

        return $stringToBeSigned;
    }
}